package rsj.proxy.parse;

import lombok.Data;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 解析dao层SQL
 *
 * @author yuanqinglong
 * @since 2021/5/24 9:06
 */
@Data
public class SqlSource {

    public SqlSource(String originalSql, String sql, List<ParameterMapping> parameterMappings) {
        this.originalSql = originalSql;
        this.sql = sql;
        this.finalSql = sql;
        this.parameterMappings = parameterMappings;
    }

    /**
     * 原始的sql、
     * 例：SELECT * FROM user WHERE user_id = #{userId} AND user_name = #{userName}
     */
    private String originalSql;

    /**
     * ?替换占位符后sql
     * 例：SELECT * FROM user WHERE user_id = ? AND user_name = ?
     */
    private String sql;

    /**
     * 最终的sql
     * IN 查询将根据参数集合元素个数 动态拼接多个 ?
     */
    private String finalSql;

    /**
     * 参数映射（占位符解析出的参数名列表）
     * 例：[userId,userName]
     */
    private List<ParameterMapping> parameterMappings;

    /**
     * 实体类参数类型、获取对应参数值调用的get方法
     * 例：userId: -> getUserId()
     * 例：userName: -> getUserName()
     */
    private Map<String, Method> getMethodMap = new HashMap<>();

    /**
     * 简单数据类型的参数名,对应方法形参下标位置
     * 例：userId: -> 0
     * 例：userName: -> 1
     */
    private Map<String, Integer> simpleParameters = new HashMap<>();


    /**
     * 设置实体类型参数，sql中占位符字段名和实体类中的get方法映射
     *
     * @param parameterType     参数类型
     * @param parameterMappings 参数映射
     * @param index             指数
     * @throws NoSuchMethodException 没有这样的方法异常
     */
    public void setGetMethod(Class<?> parameterType, List<ParameterMapping> parameterMappings, int index) throws NoSuchMethodException {
        if (!simpleParameters.isEmpty()) {
            throw new IllegalArgumentException("不支持实体类型参数和简单数据类型参数同时存在！！！");
        }
        if (!getMethodMap.isEmpty()) {
            throw new IllegalArgumentException("不支持多个实体类型参数！！！");
        }
        Map<String, Field> fieldMap = Stream.of(parameterType.getDeclaredFields()).collect(Collectors.toMap(Field::getName, Function.identity()));
        for (ParameterMapping parameterMapping : parameterMappings) {
            String placeholderName = parameterMapping.getPlaceholderName();
            Field field = fieldMap.get(placeholderName);
            if (field == null) {
                throw new IllegalArgumentException(parameterType.getName() + " 对象中没有与 " + placeholderName + " 名称相同的属性");
            }
            if (!BeanUtils.isSimpleProperty(field.getType())) {
                throw new IllegalArgumentException(field.getType() + " 不支持复杂数据类型属性映射！！！");
            }
            parameterMapping.setMethodParamIndex(index);
            parameterMapping.setMethodParamTypeEnum(ParamTypeEnum.ENTITY);
            String fieldName = field.getName();
            Method declaredMethod = parameterType.getDeclaredMethod("get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1));
            getMethodMap.put(fieldName, declaredMethod);
        }
        //for (Field field : parameterType.getDeclaredFields()) {
        //    String fieldName = field.getName();
        //    if (!BeanUtils.isSimpleProperty(field.getType())) {
        //        throw new IllegalArgumentException(fieldName + " 不支持非简单数据类型属性映射！！！");
        //    }
        //    Method declaredMethod = parameterType.getDeclaredMethod("get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1));
        //    getMethodMap.put(fieldName, declaredMethod);
        //}
    }

    /**
     * 设置简单的参数
     *
     * @param parameterName 参数名称
     * @param index         指数
     */
    public void setSimpleParameters(String parameterName, Integer index) {
        if (!getMethodMap.isEmpty()) {
            throw new IllegalArgumentException("不支持简单数据类型参数和实体类型参数同时存在！！！");
        }
        simpleParameters.put(parameterName, index);
    }


}
